package com.wang.java.thread.threadlocal;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 线程本地变量，采用线程本地变量副本的方式解决多线程问题
 * 需注意的问题：ThreadLocal使用不当可能导致内存泄露
 */
public class ThreadLocalTest {

    static ThreadLocal<String> threadLocal = new ThreadLocal<>();

    public static void main(String[] args) {
//        testThreadLocal();
        testThreadThreadLocals();
    }

    /**
     * 在最后一行加断点，DEBUG查看thread.threadLocals中值为hello的key值是否被垃圾回收
     * 未设置threadLocal= null时，thread.threadLocals[i].value="hello"，thread.threadLocals[i].referent=null，未被垃圾回收，因为当前类成员变量threadLocal还保留着对referent的强引用
     * 设置threadLocal = null时，thread.threadLocals[i].value="hello"，thread.threadLocals[i].referent=null，被垃圾回收回收
     */
    private static void testThreadThreadLocals() {
        String str = "hello";
        Thread thread = Thread.currentThread();
        threadLocal.set(str);
        threadLocal = null;
        System.gc();
        System.out.println();
    }


    /**
     * 测试ThreadLocal变量是线程的本地变量，多个线程互不影响
     * 控制台输出结果：
     * pool-1-thread-1->pool-1-thread-1
     * pool-1-thread-2->pool-1-thread-2
     */
    private static void testThreadLocal() {
        Runnable runnable = () -> {
            String currentThreadName = Thread.currentThread().getName();
            threadLocal.set(currentThreadName);
            String threadLocalValue = threadLocal.get();
            System.out.println(currentThreadName + "->" + threadLocalValue);
        };
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(runnable);
        executorService.submit(runnable);
        executorService.shutdown();
    }
}
